package com.simple3d.primitives
{
	import __AS3__.vec.Vector;
	
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.display.TriangleCulling;
	import flash.geom.Matrix3D;
	import flash.geom.Utils3D;
	import flash.geom.Vector3D;
		
	/**
	 * The cylinder class lets you render a cylinder.
	 * @author Pradeek 
	 */
	public class Cylinder extends Sprite
	{
		private var rows:int = 32;
		private var cols:int = 16;
		private var ix:Number;
		private var iy:Number;
		private var displayMode:uint = 0;
		
		protected var matrix3d:Matrix3D;
		protected var paraVector:Vector3D;
		protected var vertices:Vector.<Number>;
		protected var projectedVertices:Vector.<Number>;
		protected var indices:Vector.<int>;
		protected var uvtData:Vector.<Number>;
		
		/**
		 *  Indicates the radius of the cone, in pixels. 
		 */		
		public var _radius:Number = 100;
		
		/**
		 * Indicates the height of the cone, in pixels. 
		 */		
		public var _height:Number = 250;
		
		/**
		 * Indicates the color of the cone. 
		 */		
		public var color:uint = 0x000000;
		
		/**
		 * Indicates the BitmapData of the texture of the cone. 
		 */				
		public var texture:BitmapData;
		
		/**
		 * Constructor 
		 * @param radius - Radius of the cylinder, in pixels
		 * @param height - Height of the cylinder, in pixels
		 * @param texture - BitmapData of the texture.
		 * 
		 */		
		public function Cylinder(radius:Number = 100, height:Number = 100, texture:BitmapData = null)
		{
			this.texture = texture;
			_radius = radius;
			_height = height;
			
			if(texture)
			{
				displayMode = 1;
			}
						
			matrix3d = new Matrix3D();
			paraVector = new Vector3D();
			vertices = new Vector.<Number>();
			projectedVertices = new Vector.<Number>();
			indices = new Vector.<int>();
			uvtData = new Vector.<Number>();
			
			calculateGeometries();
		}
		
		protected function calculateGeometries():void
		{
			/* Calculate vertices */
			for(var i:int = 0; i<rows; i++)
			{
				ix = i/(rows-1)*Math.PI*2.0;
				
				for(var j:int = 0; j<cols; j++)
				{
					iy = (j/(cols-1) - 0.5)*Math.PI;
					
					// Get vertices using parametric co-ordinates of a cylinder
					paraVector = new Vector3D(Math.cos(ix), iy, Math.sin(ix));
					//Collect vetices in the verts Vector array
					vertices.push(_radius*paraVector.x,_height*paraVector.y,_radius*paraVector.z);
					//Load uvt data
					uvtData.push( i/(rows-1),j/(cols-1), 0.0);
				}
			}
			
			//Create indices
			var ii:int =0;
			for (var ik:int=0 ; ik!=rows-1; ik++) 
			{
				for (var jk:int=0 ; jk!=cols-1; jk++) 
				{
					indices.push( ii,ii+cols+1,ii+1,
					ii+cols,ii+cols+1,ii++);
				}
				ii++;
			}				
		}
		
		/**
		 *  Renders the cylinder. 
		 */		
		public function render():void
		{
			Utils3D.projectVectors(matrix3d,vertices,projectedVertices,uvtData);
			
			this.graphics.clear();
			switch(displayMode)
			{
				case 0:
					this.graphics.beginFill(color);
					this.graphics.lineStyle(1,color);
					this.graphics.drawTriangles(projectedVertices,indices);
					break;
				case 1:
					this.graphics.beginBitmapFill(this.texture,null,false,false);
					this.graphics.drawTriangles(projectedVertices,indices,uvtData,TriangleCulling.NEGATIVE);
					break;
			}
			this.graphics.endFill();			
		}
		
		/**
		 *  Rotate the 3D object on all axes.
		 *  @param value - amount of rotation.
		 */		
		public function rotate(value:Number):void
		{  
			matrix3d.appendRotation(value,Vector3D.X_AXIS);
			matrix3d.appendRotation(value,Vector3D.Y_AXIS);
			matrix3d.appendRotation(value,Vector3D.Z_AXIS);
		}	
		
		public override function set rotationX(value:Number):void
		{
			matrix3d.appendRotation(value,Vector3D.X_AXIS);
		}
		
		public override function set rotationY(value:Number):void
		{
			matrix3d.appendRotation(value,Vector3D.Y_AXIS);
		}
		
		public override function set rotationZ(value:Number):void
		{
			matrix3d.appendRotation(value,Vector3D.Z_AXIS);
		}		
	}
}